package com.yet.config;

import java.beans.PropertyDescriptor;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.env.PropertySource;

import com.yet.annotation.YetConfig;
import com.yet.center.ConfigCenter;
import com.yet.listener.YetListener;
import com.yet.source.CenterPropertySource;
import com.yet.source.CenterPropertyValues;
import com.yet.source.PropertySourcesPropertyResolverHolder;
import com.yet.source.SourceAutowirePostProcessor;

/**
 * XxlConf Factory
 *
 * @author xuxueli 2015-9-12 19:42:49
 */
public class SpringAutowireHandler extends InstantiationAwareBeanPostProcessorAdapter
		implements ApplicationContextAware {

	public static final Logger logger = LoggerFactory.getLogger(SpringAutowireHandler.class);

	private ConfigCenter configCenter;

	private ApplicationContext context;

	private PropertySource<Map<String, Object>> propertySource;

	@Override
	public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,
			String beanName) throws BeansException {
		Class<? extends Object> clz = bean.getClass();
		if (clz.isAnnotationPresent(YetConfig.class)) {
			if (this.configCenter == null) {
				initCenter();
			}
			CenterPropertyValues<Map<String, Object>> centerPropertyValues = new CenterPropertyValues<Map<String, Object>>(
					propertySource, clz);
			Collection<SourceAutowirePostProcessor> sourceAutowirePostProcessors = getSourceAutowirePostProcessors();
			sourceAutowirePostProcessors
					.forEach(s -> s.postProcessAfterCenterAutowire(centerPropertyValues, bean, beanName));
			return centerPropertyValues;
		}
		return super.postProcessPropertyValues(pvs, pds, bean, beanName);
	}

	private void initCenter() {
		this.configCenter = context.getBean(ConfigCenter.class);
		this.propertySource = new CenterPropertySource(configCenter);
		PropertySourcesPropertyResolverHolder.init(this.propertySource);
		registryListener();
	}

	private void registryListener() {
		this.configCenter.subscribe(null, (YetListener) context.getBean(SourceAutowirePostProcessor.class));
	}

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.context = applicationContext;
	}

	public Collection<SourceAutowirePostProcessor> getSourceAutowirePostProcessors() {
		Map<String, SourceAutowirePostProcessor> processors = this.context
				.getBeansOfType(SourceAutowirePostProcessor.class);
		if (processors != null && processors.size() > 0) {
			return processors.values();
		}
		return Collections.emptyList();
	}
}
